#include "MySQLConnection.h"

MySQLConnection::MySQLConnection(const string &database,
                                 const string &username,
                                 const string &password,
                                 const string &host,
                                 int port)
        : MySQLConnection("MyConnection",
                          database,
                          username,
                          password,
                          host,
                          port) {
}

MySQLConnection::MySQLConnection(string connectionName,
                                 const string &database,
                                 const string &username,
                                 const string &password,
                                 const string &host,
                                 int port) :
        connectionName_(std::move(connectionName)),
        database_(database) {
    mysql_init(&connection);
    mysql_options(&connection, MYSQL_SET_CHARSET_NAME, "UTF8");
    if (!(mysql_real_connect(&connection,
                             host.c_str(),
                             username.c_str(),
                             password.c_str(),
                             database.c_str(),
                             port,
                             NULL,
                             0)
    )) {
        LOG_FATAL << connectionName_ << "连接数据库错误 : " << mysql_error(&connection);
    } else {
        LOG_DEBUG << "连接" << connectionName_ << "成功连接到数据库[" << database << "]";
    }
    if (mysql_query(&connection, "set names utf8")) {
        LOG_ERROR << "连接" << connectionName_ << "设置编码失败 : " << mysql_errno(&connection);
    }

    //设置编码格式
    /*
     * mysql_query 返回值为 0 表示成功, 其他返回值都是失败
     * CR_COMMANDS_OUT_OF_SYNC : 以不恰当的顺序执行了命令
     * CR_SERVER_GONE_ERROR : MySQL服务器不可用
     * CR_SERVER_LOST : 在查询过程中，与服务器的连接丢失
     * CR_UNKNOWN_ERROR : 出现未知错误。
      */
}

MySQLConnection::~MySQLConnection() {
    mysql_close(&connection);
    LOG_DEBUG << "连接" << connectionName_ << "[" << database_ << "]" << "成功释放";
}

bool MySQLConnection::query(const string &sql) {
    MutexLockGuard lock(mutex_);
    if (mysql_query(&connection, sql.c_str())) {
        LOG_ERROR << "执行更新语句 [" << sql << "] 失败, 失败原因" << mysql_errno(&connection);
        return false;
    } else {
        return true;
    }
}

MySQLConnection::fieldsVector MySQLConnection::select(const string &sql) {
    {
        MutexLockGuard lock(mutex_);
        if (mysql_real_query(&connection, sql.c_str(), sql.size())) {
            LOG_ERROR << "执行查询语句 [" << sql << "] 失败, 失败原因" << mysql_errno(&connection);
            return {};
        }
    }
    MYSQL_RES *queryRes;//这个结构代表返回行的一个查询结果集
    if (!(queryRes = mysql_store_result(&connection))) {
        LOG_ERROR << "获取查询语句 [" << sql << "] 结果失败, 失败原因" << mysql_errno(&connection);
        return {};
    }

    unsigned int column = mysql_num_fields(queryRes);
    fieldsVector res;
    {
        fields fieldNames(column);
        for (unsigned int i = 0; i < column; ++i) {
            fieldNames[i] = string(mysql_fetch_field(queryRes)->name);
        }
        res.push_back(fieldNames);
    }

    {
        MYSQL_ROW row;//一个行数据的类型安全(type-safe)的表示
        while (row = mysql_fetch_row(queryRes)) {
            fields fields(column);
            for (unsigned int i = 0; i < column; ++i) {
                fields[i] = string(row[i]);
            }
            res.push_back(fields);
        }
    }

    mysql_free_result(queryRes);
    return res;

}

